﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Reflection;

public abstract class QColumnBase
{
    public string Alias { get; set; }
}

public class QConstant : QColumnBase, IQEvaluable
{
    public Object Constant { get; set; }


    public QConstant(Object constant)
    {
        this.Constant = constant;
    }
    public QConstant(Object constant, string alias)
    {
        this.Constant = constant;
        this.Alias = alias;
    }
    public string Evalute()
    {
        return QueryUtil.FormatValue(this.Constant);
    }


    public string EvaluteWithAlias()
    {
        return QueryUtil.FormatValue(this.Constant) + (this.Alias == null ? "" : " " + this.Alias);
    }
}

public class QColumn : QColumnBase, IQEvaluable
{
    public string Name { get; set; }

    public QColumn(string name)
    {
        this.Name = name;
    }
    public QColumn(string name, string alias)
    {
        this.Name = name;
        this.Alias = alias;
    }

    public string Evalute()
    {
        return this.Name;
    }

    public string EvaluteWithAlias()
    {
        return this.Name + (this.Alias == null ? "" : " " + this.Alias);
    }
}

public class QFunction : QColumnBase, IQEvaluable
{
    public IQEvaluable Function { get; set; }

    public QFunction(IQEvaluable function)
    {
        this.Function = function;
    }
    public QFunction(IQEvaluable function, string alias)
    {
        this.Function = function;
        this.Alias = alias;
    }

    public string Evalute()
    {
        return this.Function.Evalute();
    }

    public string EvaluteWithAlias()
    {
        return this.Function.Evalute() + (this.Alias == null ? "" : " " + this.Alias);
    }
}

public class QSubQuery : QColumnBase, IQEvaluable
{
    public QueryFacade Query { get; set; }


    public QSubQuery(QueryFacade query)
    {
        this.Query = query;
    }
    public QSubQuery(QueryFacade query, string alias)
    {
        this.Query = query;
        this.Alias = alias;
    }
    public string Evalute()
    {
        return "(" + this.Query.ToString() + ")";
    }


    public string EvaluteWithAlias()
    {
        return "(" + this.Query.ToString() + ")" + (this.Alias == null ? "" : " " + this.Alias);
    }
}

public class QCase : QColumnBase, IQEvaluable
{
    public IList<QWhenThen> WhenThenList { get; set; }
    public IQEvaluable ElseResult { get; set; }

    public QCase(params QWhenThen[] whenthens)
        : this(elseResult: null, whenthens: whenthens)
    {

    }

    public QCase(IQEvaluable elseResult, params QWhenThen[] whenthens)
    {
        this.ElseResult = elseResult;
        this.WhenThenList = whenthens.ToList<QWhenThen>();
    }

    public string Evalute()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("(case ");
        foreach (QWhenThen whenthen in this.WhenThenList)
        {
            sb.AppendLine(" when " + whenthen.When.Evalute() + " then " + whenthen.Then.Evalute());
        }
        if (this.ElseResult != null)
        {
            sb.AppendLine(" else " + this.ElseResult.Evalute());
        }
        sb.Append("end )");
        return sb.ToString();
    }

    public string EvaluteWithAlias()
    {
        return this.Evalute() + (this.Alias == null ? "" : " " + this.Alias);
    }
}

public class QWhenThen
{
    public IQEvaluable When { get; set; }
    public IQEvaluable Then { get; set; }
    public QWhenThen(IQEvaluable when, IQEvaluable then)
    {
        this.When = when; this.Then = then;
    }
}
